﻿using CoreDomain.BusinessCore;
using DomainService.IService;
using DomainService.IService.Sys;
using Infrastructure;
using Infrastructure.IRepository.Sys;
using Model;
using Model.BusinessModel;
using Model.BusinessModel.InPut;
using Model.BusinessModel.MatchFormula;
using Model.BusinessModel.OutPut;
using Model.BusinessModel.OutPut.sys;
using Newtonsoft.Json.Linq;
using System.Data;
using System.Reflection.Emit;
using System.Text.Json;
using Utility;
using Utility.Enum;

namespace DomainService.Service.Sys
{
    /// <summary>
    /// 数据规则服务接口实现
    /// </summary>
    public class SysDataRuleService : ISysDataRuleService
    {
        #region 构造实例化

        //仓储接口
        private readonly ISysDataRuleRepository _sysDataRuleRepository;
        /// <summary>
        /// 菜单仓储接口
        /// </summary>
        private readonly ISysMenuRepository _menuRepository;
        /// <summary>
        /// 按钮仓储接口
        /// </summary>
        private readonly ISysButtonRepository _buttonRepository;

        /// <summary>
        /// 菜单数据列接口
        /// </summary>
        private readonly ISysMenuTableColsRepository _menuTableColsRepository;

        /// <summary>
        /// 数据规则配置仓储接口
        /// </summary>
        private readonly ISysDataRuleConfigRepository _sysDataRuleConfigRepository;

        /// <summary>
        /// 基础服务
        /// </summary>
        private readonly IBaseService _baseService;

        /// <summary>
        /// 构造函数 实现依赖注入
        /// </summary>
        public SysDataRuleService(ISysDataRuleRepository sysDataRuleRepository, ISysMenuRepository menuRepository, ISysButtonRepository buttonRepository, ISysMenuTableColsRepository menuTableColsRepository, ISysDataRuleConfigRepository sysDataRuleConfigRepository, IBaseService baseService)
        {
            _sysDataRuleRepository = sysDataRuleRepository;
            _menuRepository = menuRepository;
            _buttonRepository = buttonRepository;
            _menuTableColsRepository = menuTableColsRepository;
            _sysDataRuleConfigRepository = sysDataRuleConfigRepository;
            _baseService = baseService;
        }

        #endregion

        #region 服务实现

        /// <summary>
        /// 新增规则数据
        /// </summary>
        /// <param name="sysDataRule"></param>
        /// <param name="loginUserMsg">登录人员信息</param>
        public ReceiveStatus Insert(SysDataRuleInput sysDataRule, LoginOutPut loginUserMsg)
        {
            ReceiveStatus receiveStatus = new ReceiveStatus();
            var result = Validate(sysDataRule);
            if (!result.success)
                return result;
            sysDataRule.RuleId = Guid.NewGuid().ToString();
            var menuModel = _menuRepository.GetByKey(sysDataRule.MenuId ?? string.Empty, BaseSqlRepository.sysMenu_selectByKeySql);
            if (menuModel == null)
            {
                return ExceptionHelper.CustomException("不存在当前菜单");
            }
            sysDataRule.CorporationKey = menuModel.CorporationKey;
            sysDataRule.SystemKey = menuModel.SystemKey;
            var matchFormulaList = JsonSerializer.Deserialize<List<MatchingDataInput>>(sysDataRule.RuleJson ?? string.Empty);
            var dataRuleConfigList = _sysDataRuleConfigRepository.GetSysDataRuleConfig(sysDataRule.MenuId ?? string.Empty).Where(f => f.ConfigType == sysDataRule.RuleType).ToList();
            var ruleData = DataAuthCore.PreviewFormula(matchFormulaList ?? [], dataRuleConfigList);
            sysDataRule.AnalysisRule = ruleData.Item1;
            sysDataRule.AnalysisRule_CN = ruleData.Item2;
            if (sysDataRule.RuleType == (int)RuleTypeEnum.DataRowRule)
            {
                sysDataRule.AnalysisRule = DataAuthCore.GetRowDataAuthRoleSql(Const.MainTableAlias, sysDataRule.MenuId ?? string.Empty, matchFormulaList ?? [], loginUserMsg.UserId);
            }

            //使用事务
            TransactionHelper.ExecuteTransaction(() =>
            {
                _sysDataRuleRepository.Insert(sysDataRule, BaseSqlRepository.sysDataRule_insertSql);
                if (sysDataRule.ButtonIds.Count > 0)
                    _buttonRepository.UpdataRuleIdByButtonId(sysDataRule.ButtonIds, sysDataRule.RuleId);
                if (sysDataRule.IsOpen)
                    SetRuleIsOpenById(sysDataRule.RuleId, sysDataRule.MenuId, sysDataRule.IsOpen, sysDataRule.RuleType);
                if (!string.IsNullOrWhiteSpace(sysDataRule.FieldId))
                {
                    _menuTableColsRepository.UpdateRuleId(sysDataRule.FieldId, sysDataRule.RuleId);
                }
            });

            return receiveStatus;
        }

        /// <summary>
        /// 修改规则数据
        /// </summary>
        /// <param name="sysDataRule"></param>
        /// <param name="loginUserMsg">登录人员信息</param>
        public ReceiveStatus Update(SysDataRuleInput sysDataRule, LoginOutPut loginUserMsg)
        {
            ReceiveStatus receiveStatus = new();
            var result = Validate(sysDataRule);
            if (!result.success)
                return result;
            var menuModel = _menuRepository.GetByKey(sysDataRule.MenuId ?? string.Empty, BaseSqlRepository.sysMenu_selectByKeySql);
            if (menuModel == null)
            {
                return ExceptionHelper.CustomException("不存在当前菜单数据");
            }
            sysDataRule.CorporationKey = menuModel.CorporationKey;
            sysDataRule.SystemKey = menuModel.SystemKey;
            var matchFormulaList = JsonSerializer.Deserialize<List<MatchingDataInput>>(sysDataRule.RuleJson ?? string.Empty);
            var dataRuleConfigList = _sysDataRuleConfigRepository.GetSysDataRuleConfig(sysDataRule.MenuId ?? string.Empty).Where(f => f.ConfigType == sysDataRule.RuleType).ToList();
            var ruleData = DataAuthCore.PreviewFormula(matchFormulaList ?? [], dataRuleConfigList);
            sysDataRule.AnalysisRule = ruleData.Item1;
            sysDataRule.AnalysisRule_CN = ruleData.Item2;
            if (sysDataRule.RuleType == (int)RuleTypeEnum.DataRowRule)
            {
                sysDataRule.AnalysisRule = DataAuthCore.GetRowDataAuthRoleSql(Const.MainTableAlias, sysDataRule.MenuId ?? string.Empty, matchFormulaList ?? [], loginUserMsg.UserId);
            }

            //使用事务
            TransactionHelper.ExecuteTransaction(() =>
            {
                _sysDataRuleRepository.Update(sysDataRule, BaseSqlRepository.sysDataRule_updateSql);
                if (sysDataRule.ButtonIds.Count > 0)
                {
                    _buttonRepository.ClearButtonRule(sysDataRule.RuleId ?? string.Empty);
                    _buttonRepository.UpdataRuleIdByButtonId(sysDataRule.ButtonIds, sysDataRule.RuleId ?? string.Empty);
                }
                if (sysDataRule.IsOpen && sysDataRule.RuleType != (int)RuleTypeEnum.DataClosRule)
                    SetRuleIsOpenById(sysDataRule.RuleId, sysDataRule.MenuId, sysDataRule.IsOpen, sysDataRule.RuleType);

                if (!string.IsNullOrWhiteSpace(sysDataRule.FieldId))
                {
                    _menuTableColsRepository.UpdateRuleId(sysDataRule.FieldId, sysDataRule.RuleId ?? string.Empty);
                }
            });

            return receiveStatus;
        }

        /// <summary>
        /// 验证
        /// </summary>
        /// <param name="sysDataRule">规则数据</param>
        /// <returns></returns>
        public ReceiveStatus Validate(SysDataRuleInput sysDataRule)
        {
            ReceiveStatus receiveStatus = new ReceiveStatus();
            /*
            新增/修改前验证
            1、相同菜单下不能有重复的规则名称
            */
            var dataRule = _sysDataRuleRepository.GetDataRuleByRuleIdOrMenuId(sysDataRule.RuleId ?? string.Empty, sysDataRule.MenuId ?? string.Empty);
            if (dataRule != null)
            {
                if (dataRule.RuleName == sysDataRule.RuleName && dataRule.RuleId.ToLower() != sysDataRule.RuleId.ToLower())
                    return ExceptionHelper.CustomException(string.Format("该菜单下已存在规则名称为【{0}】的数据,请重新输入", sysDataRule.RuleName));
            }

            return receiveStatus;
        }

        /// <summary>
        /// 设置规则是否启用
        /// 同一个菜单、同一个规则类型，只能启用一个规则
        /// </summary>
        /// <param name="ruleId">规则主键</param>
        /// <param name="menuId">菜单id</param>
        /// <param name="isOpen">是否打开</param>
        /// <param name="rowAuthType">行权限类型</param>
        public ReceiveStatus SetRuleIsOpenById(string? ruleId, string? menuId, bool isOpen, int rowAuthType)
        {
            ReceiveStatus receiveStatus = new ReceiveStatus();
            if (string.IsNullOrWhiteSpace(ruleId))
                return ExceptionHelper.CustomException("请选择规则");
            if (string.IsNullOrWhiteSpace(menuId))
                return ExceptionHelper.CustomException("请选择菜单");

            TransactionHelper.ExecuteTransaction(() =>
            {
                //先把当前菜单下所有的规则改为false
                _sysDataRuleRepository.UpdateIsOpenByMenuId(menuId, false, rowAuthType);
                //在设置当前数据是否开启状态
                _sysDataRuleRepository.UpdateIsOpenById(ruleId, isOpen, rowAuthType);
            });
            return receiveStatus;
        }

        /// <summary>
        /// 获取菜单数据规则数据
        /// </summary>
        /// <param name="menuId">菜单ID</param>
        /// <param name="ruleType">规则类型</param>
        /// <returns>返回规则数据</returns>
        public ReceiveStatus<SysDataRuleOutPut> GetMenuDataRuleList(string menuId, int ruleType)
        {
            ReceiveStatus<SysDataRuleOutPut> receiveStatus = new();
            if (string.IsNullOrEmpty(menuId))
                return ExceptionHelper<SysDataRuleOutPut>.CustomExceptionData("菜单模块不能为空！");

            var list = _sysDataRuleRepository.GetMenuDataRuleList(menuId, ruleType);
            receiveStatus.data = list;
            return receiveStatus;
        }

        /// <summary>
        ///  获取数据规则
        /// </summary>
        /// <param name="pageResultModel">分页模型</param>
        /// <returns>返回规则数据</returns>
        public PageResultModel<SysDataRuleOutPut> GetDataRuleList(PageResultModel pageResultModel)
        {
            var selectWhere = string.Empty;
            JObject jobj = JObject.Parse(pageResultModel.filterJson ?? "");
            var menuId = jobj["MenuId"].ToString();
            var corporationKey = jobj["CorporationKey"].ToString();
            var systemKey = jobj["SystemKey"].ToString();
            var ruleType = Convert.ToInt32(jobj["RuleType"]);

            if (!string.IsNullOrWhiteSpace(menuId))
            {
                var menuModel = _menuRepository.GetByKey(menuId, BaseSqlRepository.sysMenu_selectByKeySql);
                var menuIdList = MenuCore.GetChildrenRoleById(menuId, menuModel.CorporationKey ?? string.Empty, menuModel.SystemKey ?? string.Empty);
                selectWhere = string.Format("and  m.Id in ('{0}')  ", string.Join("','", menuIdList.ToArray()));
            }
            if (!string.IsNullOrWhiteSpace(corporationKey))
                selectWhere += string.Format(" and sd.CorporationKey = '{0}' ", corporationKey);
            if (!string.IsNullOrWhiteSpace(systemKey))
                selectWhere += string.Format(" and sd.SystemKey = '{0}' ", systemKey);
            if (ruleType != 0)
                selectWhere += string.Format(" and sd.RuleType = '{0}' ", ruleType);

            var result = _baseService.GetAuthWhere(RuleTypeEnum.DataRowRule, "sd");
            string? authWhere = string.Empty;
            if (result.success) { authWhere = result.data[0]; }
            else
                ExceptionHelper.ThrowBusinessException(result.msg);

            pageResultModel.selectWhere = selectWhere + authWhere;

            pageResultModel.tableField = " m.Name as MenuName,m.CorporationKey,ss.SystemName,sc.CorporationName,ss.SystemKey,su.UserName,sd.RuleId,sd.MenuId,sd.RuleName,sd.RuleType,sd.RuleJson,sd.AnalysisRule,sd.AnalysisRule_CN,sd.IsOpen,sd.Remark,sd.Sort,sd.CreateTime,sd.CreateUser";
            pageResultModel.tableName = @" Sys_DataRule as sd 
                                            inner join Sys_Corporation as sc on sc.CorporationKey = sd.CorporationKey
                                            inner join Sys_System as ss on sd.SystemKey = ss.SystemKey
                                            inner join  Sys_Menu as m  on sd.MenuId = m.Id
                                            inner  join Sys_User as su on su.UserId = sd.CreateUser  ";
            pageResultModel.orderByField = " sd.Sort ";
            pageResultModel.sortType = " desc ";
            var list = _sysDataRuleRepository.GetPageList<SysDataRuleOutPut>(pageResultModel);

            return list;
        }

        /// <summary>
        /// 获取当前规则使用按钮
        /// </summary>
        /// <param name="ruleId"></param>
        /// <returns></returns>
        public ReceiveStatus<string> GetUseDataRuleButton(string ruleId)
        {
            if (string.IsNullOrEmpty(ruleId))
                return ExceptionHelper<string>.CustomExceptionData("规则id不能为空！");
            var dataRule = _sysDataRuleRepository.GetByKey(ruleId, BaseSqlRepository.sysDataRule_selectByKeySql);
            if (dataRule == null)
                return ExceptionHelper<string>.CustomExceptionData("当前规则不存在或已删除！");
            ReceiveStatus<string> receiveStatus = new();
            var buttonIds = _sysDataRuleRepository.GetUseDataRuleButton(ruleId);
            receiveStatus.data = buttonIds;
            return receiveStatus;
        }

        /// <summary>
        /// 获取数据权限配置
        /// </summary>
        /// <param name="menuId">菜单id</param>
        /// <param name="configType">配置类型</param>
        /// <returns></returns>
        public ReceiveStatus<MatchFormulaDataSourceOutPut> GetDataRuleConfig(string menuId, int configType)
        {
            if (string.IsNullOrEmpty(menuId))
                return ExceptionHelper<MatchFormulaDataSourceOutPut>.CustomExceptionData("菜单id不能为空！");

            ReceiveStatus<MatchFormulaDataSourceOutPut> receiveStatus = new ReceiveStatus<MatchFormulaDataSourceOutPut>();

            //配置数据源
            var list = _sysDataRuleConfigRepository.GetSysDataRuleConfig(menuId).Where(f => f.ConfigType == configType).ToList();

            //添加默认权限
            if (configType != (int)RuleTypeEnum.DataButtonRule)
                list.AddRange(DataAuthCore.DefaultAuthList());
            var configList = GetMenuRowAuthConfig(list);
            receiveStatus.data = configList;
            receiveStatus.msg = "获取成功";
            return receiveStatus;
        }
        /// <summary>
        /// 获取菜单权限配置
        /// </summary>
        /// <param name="sysDataRuleConfigList">行权限配置</param>
        /// <returns></returns>
        public List<MatchFormulaDataSourceOutPut> GetMenuRowAuthConfig(List<SysDataRuleConfig> sysDataRuleConfigList)
        {
            List<MatchFormulaDataSourceOutPut> matchFormulaDataSourceList = new List<MatchFormulaDataSourceOutPut>();
            if (sysDataRuleConfigList == null || sysDataRuleConfigList.Count == 0)
                return matchFormulaDataSourceList;
            foreach (var item in sysDataRuleConfigList.Where(f => f.IsOpen))
            {
                MatchFormulaDataSourceOutPut model = new()
                {
                    ConfigId = item.ConfigId,
                    label = item.PermissionsFieldName,
                    value = item.PermissionsField,
                    ShowControl = item.ShowControl
                };
                if (item.ShowControl != (int)ShowControlEnum.Input && (item.ShowControl == (int)ShowControlEnum.RadioSelect))
                    model.ConditionalEquationValueList = new List<SelectOutPut>();

                model.ConditionalEquationList = GetConditionalEquationList(item.ConditionalEquationValue);
                model.ShowControlDataSource = item.ShowControlDataSource;
                model.disabled = !item.IsOpen;
                model.ShowControlName = EnumHelper.GetName<ShowControlEnum>(item.ShowControl);
                model.ShowControlDataSourceName = EnumHelper.GetName<ShowControlDataSourceEnum>(item.ShowControlDataSource);
                matchFormulaDataSourceList.Add(model);
            }

            return matchFormulaDataSourceList;
        }

        /// <summary>
        /// 获取所有条件等式下拉项
        /// </summary>
        /// <returns></returns>
        public List<SelectOutPut> GetAllConditionalEquationList()
        {
            List<SelectOutPut> layuiSelectList = new()
            {
                new SelectOutPut { label = ConditionalEquationValueEnum.等于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.等于) },
                new SelectOutPut { label = ConditionalEquationValueEnum.不等于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.不等于) },
                new SelectOutPut { label = ConditionalEquationValueEnum.大于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.大于) },
                new SelectOutPut { label = ConditionalEquationValueEnum.大于等于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.大于等于) },
                new SelectOutPut { label = ConditionalEquationValueEnum.小于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.小于) },
                new SelectOutPut { label = ConditionalEquationValueEnum.小于等于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.小于等于) },
                new SelectOutPut { label = ConditionalEquationValueEnum.包含.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.包含) },
                new SelectOutPut { label = ConditionalEquationValueEnum.不包含.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.不包含) }
            };
            return layuiSelectList;
        }

        /// <summary>
        /// 获取条件等式下拉项
        /// </summary>
        /// <param name="conditionalEquation">位域枚举值</param>
        /// <returns></returns>
        public List<SelectOutPut> GetConditionalEquationList(int conditionalEquation)
        {
            List<SelectOutPut> layuiSelectList = new();
            ConditionalEquationValueEnum conditionalEquationEnum = (ConditionalEquationValueEnum)conditionalEquation;
            if (conditionalEquationEnum.HasFlag(ConditionalEquationValueEnum.等于))
                layuiSelectList.Add(new SelectOutPut { label = ConditionalEquationValueEnum.等于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.等于) });
            if (conditionalEquationEnum.HasFlag(ConditionalEquationValueEnum.不等于))
                layuiSelectList.Add(new SelectOutPut { label = ConditionalEquationValueEnum.不等于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.不等于) });
            if (conditionalEquationEnum.HasFlag(ConditionalEquationValueEnum.大于))
                layuiSelectList.Add(new SelectOutPut { label = ConditionalEquationValueEnum.大于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.大于) });
            if (conditionalEquationEnum.HasFlag(ConditionalEquationValueEnum.大于等于))
                layuiSelectList.Add(new SelectOutPut { label = ConditionalEquationValueEnum.大于等于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.大于等于) });
            if (conditionalEquationEnum.HasFlag(ConditionalEquationValueEnum.小于))
                layuiSelectList.Add(new SelectOutPut { label = ConditionalEquationValueEnum.小于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.小于) });
            if (conditionalEquationEnum.HasFlag(ConditionalEquationValueEnum.小于等于))
                layuiSelectList.Add(new SelectOutPut { label = ConditionalEquationValueEnum.小于等于.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.小于等于) });
            if (conditionalEquationEnum.HasFlag(ConditionalEquationValueEnum.包含))
                layuiSelectList.Add(new SelectOutPut { label = ConditionalEquationValueEnum.包含.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.包含) });
            if (conditionalEquationEnum.HasFlag(ConditionalEquationValueEnum.不包含))
                layuiSelectList.Add(new SelectOutPut { label = ConditionalEquationValueEnum.不包含.ToString(), value = EnumHelper.GetDescription(ConditionalEquationValueEnum.不包含) });
            return layuiSelectList;
        }
        #endregion
    }
}
